#!/usr/bin/env python
# coding=utf-8
'''
作    者 : 北极星光 light22@126.com
创建时间 : 2025-06-05 09:22:54
最后修改 : 2025-06-28 10:16:28
修 改 者 : 北极星光
'''

# 接口文档：https://napcat.apifox.cn/
#          https://github.com/botuniverse/onebot-11/blob/master/api/public.md

import re
import time
import json
import asyncio
import websockets
import yaml
import logging
from apps.tools import *
from apps.DeepseekAI import DeepseekAI
from apps.ernieAI import ErnieAI
from websockets.exceptions import ConnectionClosed
from logging import getLogger, FileHandler

with open('./config/ncbot_config.yaml', 'r', encoding='utf-8') as f:
    bot_cfg = yaml.load(f, Loader=yaml.FullLoader)
with open('./config/ds_config.yaml', 'r', encoding='utf-8') as f:
    ds_cfg = yaml.load(f, Loader=yaml.FullLoader)
with open('./config/ernie_config.yaml', 'r', encoding='utf-8') as f:
    ernie_cfg = yaml.load(f, Loader=yaml.FullLoader)

# 获取日志级别配置
log_level = bot_cfg.get('log_level')
log_file_level = bot_cfg.get('log_file_level')

# 将字符串级别转换为 logging 常量
log_level = getattr(logging, log_level.upper(), logging.INFO)
log_file_level = getattr(logging, log_file_level.upper(), logging.INFO)

# 创建专用日志记录器
_log = getLogger('ncbot')
_log.setLevel(log_level)

if not _log.handlers:
    # 详细日志格式
    detailed_format = '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s - %(message)s'
    formatter = logging.Formatter(detailed_format)

    # 创建并配置专属文件处理器
    nc_file_handler = FileHandler(
        filename=f'./logs/ncbot_{time.strftime("%Y-%m-%d")}.log',
        mode='a',
        encoding='utf-8')
    nc_file_handler.setLevel(log_file_level)
    nc_file_handler.setFormatter(formatter)

    # 创建控制台处理器
    nc_console_handler = logging.StreamHandler()
    nc_console_handler.setLevel(log_level)
    nc_console_handler.setFormatter(formatter)

    # 只添加到专用记录器
    _log.addHandler(nc_file_handler)
    _log.addHandler(nc_console_handler)

    # 详细的调试信息
    # _log.debug("="*80)
    # _log.debug("日志系统初始化完成")
    # _log.debug("日志记录器名称: %s", _log.name)
    # _log.debug("日志级别: %s", logging.getLevelName(_log.level))
    # _log.debug("处理器数量: %d", len(_log.handlers))
    # for i, handler in enumerate(_log.handlers, 1):
    #     _log.debug("处理器 #%d: %s", i, handler.__class__.__name__)
    #     _log.debug("  级别: %s", logging.getLevelName(handler.level))
    # _log.debug("="*80)

# 实例化DeepseekAI
deepseek_ai = DeepseekAI(api_key=ds_cfg.get('api_key'),
                         model_name=ds_cfg.get('model_name'),
                         bot_name=ds_cfg.get('bot_name'),
                         bot_role=ds_cfg.get('bot_role'),
                         welcome_words=ds_cfg.get('welcome_words'),
                         sensitive_words=ds_cfg.get('sensitive_words'))
# 实例化ErnieAI
ernie_ai = ErnieAI(api_key=ernie_cfg.get('api_key'),
                   bot_name=ernie_cfg.get('bot_name'),
                   bot_role=ernie_cfg.get('bot_role'),
                   welcome_words=ernie_cfg.get('welcome_words'),
                   sensitive_words=ernie_cfg.get('sensitive_words'))

async def handler(websocket, path):
    client_ip = websocket.remote_address[0]
    _log.info(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 客户端 {client_ip} 连接成功")

    try:
        # 获取登录信息
        login_payload = {
            "action": "get_login_info",
            "params": {},
            "echo": "login_verify_123"
        }
        await websocket.send(json.dumps(login_payload))
        while True:
            login_info = json.loads(await websocket.recv())
            if login_info.get('echo') == 'login_verify_123':
                break
        self_id = login_info.get('data').get('user_id')
        self_nickname = login_info.get('data').get('nickname')
        _log.info(
            f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 机器人登录成功：{self_nickname}({self_id})"
        )

        # 监听消息
        try:
            async for message in websocket:

                try:
                    message = json.loads(message)
                    message_type = message.get('message_type')

                    # 处理群消息
                    if message_type == 'group':
                        group_id = message.get('group_id')
                        user_id = message.get('user_id')
                        nickname = message.get('sender').get('nickname')
                        user = f'{nickname}({user_id})'
                        raw_message = message.get('raw_message')

                        # 过滤自己发送的消息
                        if user_id == self_id:
                            continue
                        # 校验群聊功能开关
                        if not bot_cfg.get('enable_group'):
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id": group_id,
                                    "message": [{
                                        "type": "text",
                                        "data": {
                                            "text": "群聊功能未开启，请联系管理员"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]群聊功能未开启，请联系管理员"
                            )
                            continue

                        _log.info(
                            f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}] QQ群<{group_id}> 收到群消息：{user}：{raw_message}"
                        )

                        # DeepseekAI对话
                        if re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]对话.*)$",
                                raw_message):
                            match = re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]对话.*)$",
                                raw_message)

                            # 构造消息发送请求数据对象
                            if match.group(2):
                                message_content = match.group(2).split(
                                    '对话')[1].strip()
                                reply_content = deepseek_ai.deepseek_chat(
                                    message_content, user=user)
                                html_path = md_to_html(
                                    reply_content,
                                    'output/output.html',
                                    welcome_words=deepseek_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )
                            else:
                                reply_content = deepseek_ai.welcome_words
                                html_path = md_to_html(reply_content,
                                                       'output/output.html')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI回复"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 列出所有模型
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]模型.*)$",
                                raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = deepseek_ai.list_models()
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI模型列表"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 查询余额
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]余额.*)$",
                                raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = deepseek_ai.get_balance()
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI余额查询"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 重置消息
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]重置.*)$",
                                raw_message):
                            deepseek_ai.reset_messages(user=user)
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "text",
                                        "data": {
                                            "text": f"回复{nickname}：会话已重置"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功重置消息 {user} "
                            )

                        # 帮助信息
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?([dD][sS]帮助.*)$",
                                raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = f'''### DeepSeekAI帮助
- /DS对话：AI对话（指令后跟对话内容）
- /DS模型：列出所有模型
- /DS余额：查询余额
- /DS重置：重置会话
- /DS帮助：显示帮助信息'''
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI帮助"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 文心一言
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心一言.*)$",
                                raw_message):
                            match = re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心一言.*)$",
                                raw_message)

                            # 构造消息发送请求数据对象
                            if match.group(2):
                                message_content = match.group(2).split(
                                    '一言')[1].strip()

                                reply_content = ernie_ai.ernie_text_generate(
                                    message_content,
                                    model_name=ernie_cfg.get(
                                        'model_name_text_generate'),
                                    user=user)
                                html_path = md_to_html(
                                    reply_content,
                                    'output/output.html',
                                    welcome_words=ernie_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )
                            else:
                                reply_content = ernie_ai.welcome_words
                                html_path = md_to_html(reply_content,
                                                       'output/output.html')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心一言"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )

                        # 文心图片生成
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心[绘画]图.*)$",
                                raw_message):
                            match = re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心[绘画]图.*)$",
                                raw_message)

                            # 构造消息发送请求数据对象
                            if match.group(2):
                                message_content = match.group(2).split(
                                    '图')[1].strip()
                                response = ernie_ai.ernie_image_generate(
                                    message_content,
                                    model_name=ernie_cfg.get(
                                        'model_name_image_generate'))
                                if response.get('error'):
                                    payload = {
                                        "action": "send_group_msg",
                                        "params": {
                                            "group_id":
                                            group_id,
                                            "message": [{
                                                "type": "text",
                                                "data": {
                                                    "text":
                                                    f"回复{nickname}：生成图片失败:{response.get('error').get('message')}"
                                                }
                                            }]
                                        }
                                    }
                                    await websocket.send(json.dumps(payload))
                                    _log.error(
                                        f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】 生成图片失败:{response.get('error').get('message')}"
                                    )
                                else:
                                    img_url = response.get('data')[0].get(
                                        'url')
                                    payload = {
                                        "action": "send_group_msg",
                                        "params": {
                                            "group_id":
                                            group_id,
                                            "message": [{
                                                "type": "image",
                                                "data": {
                                                    "file": img_url,
                                                    "summary": "文心图片生成"
                                                }
                                            }]
                                        }
                                    }
                                    await websocket.send(json.dumps(payload))
                                    _log.info(
                                        f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】生成图片成功: {user}"
                                    )

                        # 列出所有模型
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心模型.*)$",
                                raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = ernie_ai.list_models()
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=ernie_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心模型列表"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )

                        # 重置会话
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心重置.*)$",
                                raw_message):
                            ernie_ai.reset_messages(user=user)
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "text",
                                        "data": {
                                            "text": f"回复{nickname}：会话已重置"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功重置消息 {user} "
                            )

                        # 帮助信息
                        elif re.match(
                                f"^(\[CQ:at,qq={self_id}\]\s+)?[/#]?(文心帮助.*)$",
                                raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = f'''### 文心一言帮助
- /文心一言：AI生成文本（指令后跟对话内容）
- /文心画图、/文心绘图：AI生成图片（指令后跟图片描述）
- /文心模型：列出所有模型
- /文心重置：重置会话
- /文心帮助：显示帮助信息'''
                            html_path = md_to_html(reply_content,
                                                   'output/output.html',welcome_words=ernie_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_group_msg",
                                "params": {
                                    "group_id":
                                    group_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心一言帮助"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )

                    # 处理私聊消息
                    elif message_type == 'private':
                        user_id = message.get('user_id')
                        nickname = message.get('sender').get('nickname')
                        user = f'{nickname}({user_id})'
                        raw_message = message.get('raw_message')

                        # 过滤自己发送的消息
                        if user_id == self_id:
                            continue
                        # 校验私聊功能开关
                        if not bot_cfg.get('enable_private'):
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "text",
                                        "data": {
                                            "text": "私聊功能未开启，请联系管理员"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}] QQ私聊<{user}> 私聊功能未开启，请联系管理员"
                            )
                            continue

                        _log.info(
                            f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}] QQ私聊<{user}> 收到私聊消息：{raw_message}"
                        )

                        # DeepSeekAI对话
                        if re.match(f"[/#]?([dD][sS]对话.*)$",
                                    raw_message):
                            match = re.match(f"[/#]?([dD][sS].*)$",
                                            raw_message)
                            message_content = match.group(1).split(
                                '对话')[1].strip()
                            
                            if message_content:
                                reply_content = deepseek_ai.deepseek_chat(
                                    message_content, user=user)
                                html_path = md_to_html(
                                    reply_content,
                                    'output/output.html',
                                    welcome_words=deepseek_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                        'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )
                            else:
                                reply_content = deepseek_ai.welcome_words
                                html_path = md_to_html(reply_content,
                                                       'output/output.html',welcome_words=deepseek_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI回复"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 列出所有模型
                        elif re.match(f"[/#]?([dD][sS]模型.*)$", raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = deepseek_ai.list_models()
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI模型列表"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 余额查询
                        elif re.match(f"[/#]?([dD][sS]余额.*)$", raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = f"当前余额：{deepseek_ai.get_balance()}"
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI余额查询"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )

                        # 帮助信息
                        elif re.match(f"[/#]?([dD][sS]帮助.*)$", raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = f'''### DeepSeekAI帮助
- /DS对话：AI对话（指令后跟对话内容）
- /DS模型：列出所有模型
- /DS余额：查询余额
- /DS重置：重置会话
- /DS帮助：显示帮助信息'''
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=deepseek_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "DeepSeekAI帮助"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【DeepSeekAI】成功回复 {user}"
                            )
                            
                        # 文心一言
                        elif re.match(f"[/#]?(文心一言.*)$", raw_message):
                            match = re.match(f"[/#]?(文心一言.*)$", raw_message)
                            message_content = match.group(1).split(
                                '一言')[1].strip()
                            if message_content:
                                reply_content = ernie_ai.ernie_text_generate(
                                    message_content,
                                    model_name=ernie_cfg.get(
                                        'model_name_text_generate'),
                                    user=user)
                                html_path = md_to_html(
                                    reply_content,
                                    'output/output.html',
                                    welcome_words=ernie_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )
                            else:
                                reply_content = ernie_ai.welcome_words
                                html_path = md_to_html(reply_content,
                                                       'output/output.html',welcome_words=ernie_ai.welcome_words)
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                                )
                                img_path = html_to_img('output/output.html',
                                                       'output/output.jpg')
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                                )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心一言回复"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )
                            
                        # 文心画图
                        elif re.match(f"[/#]?(文心[绘画]图.*)$", raw_message):
                            match = re.match(f"[/#]?(文心[绘画]图.*)$", raw_message)
                            message_content = match.group(1).split(
                                '图')[1].strip()
                            if message_content:
                                response = ernie_ai.ernie_image_generate(
                                    message_content,
                                    model_name=ernie_cfg.get(
                                        'model_name_image_generate'))
                                if response.get('error'):
                                    payload = {
                                        "action": "send_private_msg",
                                        "params": {
                                            "user_id":
                                            user_id,
                                            "message": [{
                                                "type": "text",
                                                "data": {
                                                    "text":
                                                    f"回复{nickname}：生成图片失败:{response.get('error').get('message')}"
                                                }
                                            }]
                                        }
                                    }
                                    await websocket.send(json.dumps(payload))
                                    _log.error(
                                        f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】 生成图片失败:{response.get('error').get('message')}"
                                    )
                                else:
                                    img_url = response.get('data')[0].get(
                                        'url')
                                    payload = {
                                        "action": "send_private_msg",
                                        "params": {
                                            "user_id":
                                            user_id,
                                            "message": [{
                                                "type": "image",
                                                "data": {
                                                    "file": img_url,
                                                    "summary": "文心图片生成"
                                                }
                                            }]
                                        }
                                    }
                                    await websocket.send(json.dumps(payload))
                                    _log.info(
                                        f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】生成图片成功: {user}"
                                    )
                            else:
                                payload = {
                                    "action": "send_private_msg",
                                    "params": {
                                        "user_id":
                                        user_id,
                                        "message": [{
                                            "type": "text",
                                            "data": {
                                                "text": f"回复{nickname}：请输入需要生成的图形内容"
                                            }
                                        }]
                                    }
                                }
                                await websocket.send(json.dumps(payload))
                                _log.info(
                                    f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】请输入需要生成的图形内容"
                                )

                        # 列出所有模型
                        elif re.match(f"[/#]?(文心模型.*)$", raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = ernie_ai.list_models()
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=ernie_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心模型列表"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )

                        # 重置会话
                        elif re.match(f"[/#]?(文心重置.*)$", raw_message):
                            ernie_ai.reset_messages(user=user)
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "text",
                                        "data": {
                                            "text": f"回复{nickname}：会话已重置"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功重置消息 {user} "
                            )

                        # 帮助信息
                        elif re.match(f"[/#]?(文心帮助.*)$", raw_message):
                            # 构造消息发送请求数据对象
                            reply_content = f'''### 文心一言帮助
- /文心一言：AI生成文本（指令后跟对话内容）
- /文心画图、/文心绘图：AI生成图片（指令后跟图片描述）
- /文心模型：列出所有模型
- /文心重置：重置会话
- /文心帮助：显示帮助信息'''
                            html_path = md_to_html(
                                reply_content,
                                'output/output.html',
                                welcome_words=ernie_ai.welcome_words)
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成HTML文件{html_path}"
                            )
                            img_path = html_to_img('output/output.html',
                                                   'output/output.jpg')
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]生成图片文件{img_path}"
                            )

                            # 根据需要回复消息
                            payload = {
                                "action": "send_private_msg",
                                "params": {
                                    "user_id":
                                    user_id,
                                    "message": [{
                                        "type": "image",
                                        "data": {
                                            "file":
                                            f"file:///{os.path.abspath(img_path)}",
                                            "summary": "文心一言帮助"
                                        }
                                    }]
                                }
                            }
                            await websocket.send(json.dumps(payload))
                            _log.info(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]【文心一言】成功回复 {user}"
                            )
                    
                    # 处理元事件
                    elif message.get('post_type') == 'meta_event':
                        if message.get('meta_event_type') == 'heartbeat':
                            # 心跳包
                            _log.debug(
                                f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}] 收到心跳包"
                            )
                    
                    # 处理发送消息返回包
                    elif message.get('status') == 'ok':
                        _log.info(
                            f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}] 发送消息成功"
                        )

                    # 处理未知消息类型
                    else:
                        _log.warning(
                            f"「{self_nickname}」 [{time.strftime('%Y-%m-%d %H:%M:%S')}]未知消息类型: {message}"
                        )

                except json.JSONDecodeError as e:
                    _log.error(f"消息解析失败: {e}")
                except Exception as e:
                    _log.exception(f"处理消息时出现意外错误: {type(e).__name__} - {str(e)}")
        except ConnectionClosed as e:
            _log.info(
                f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 客户端 {client_ip} 断开连接: 代码[{e.code}] 原因[{e.reason}]"
            )
        except (ConnectionResetError, OSError) as e:
            _log.error(f"网络连接异常: {type(e).__name__} - {str(e)}")
    except Exception as e:
        _log.exception(f"处理消息时出现意外错误: {type(e).__name__} - {str(e)}")
    finally:
        _log.info(f"连接 {client_ip} 处理结束")


# 增强服务器稳定性配置
async def run_websocket_server():
    async with websockets.serve(
        handler,
        bot_cfg.get('listen_host'),
        bot_cfg.get('listen_port'),
        ping_interval=20,
        ping_timeout=60,
        close_timeout=1,
        max_size=2**20  # 1MB
    ) as server:
        await server.serve_forever()  # 保持服务器持续运行

# 启动服务器
def ncbot_run():
    if bot_cfg.get('enable_ncbot') == True:
        _log.info(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}]NCBot启动成功")
        _log.info(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}]服务器监听地址：ws://{bot_cfg.get('listen_host')}:{bot_cfg.get('listen_port')}")
        _log.info(f"正在等待连接...")
        asyncio.run(run_websocket_server())


if __name__ == '__main__':
    ncbot_run()
